package com.zb.system.service.impl;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.zb.constant.AccountConstant;
import com.zb.constant.RedisConstant;
import com.zb.entity.*;
import com.zb.enums.DeviceType;
import com.zb.exception.SMSException;
import com.zb.extend.NetworkEmpRelationExtend;
import com.zb.redis.RedisLoginTokenUtil;
import com.zb.redis.RedisUtil;
import com.zb.secure.BCryptUtil;
import com.zb.service.*;
import com.zb.system.entity.CustomerRoleVo;
import com.zb.system.entity.LoginCustomerVo;
import com.zb.system.service.LoginService;
import com.zb.util.PCSmsUtil;
import com.zb.utils.TokenUtil;
import com.zb.utils.VerificUtil;
import com.zb.vo.LoginVo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.security.auth.login.LoginException;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

/**
 * @Author WEN
 * @Date 2023/7/19 0019
 **/
@Service
public class LoginServiceImpl implements LoginService {
    @Resource
    private ZjAccountService accountService;
    @Resource
    private ZjEmpService empService;
    @Resource
    private ZjCustomerService customerService;
    @Resource
    private ZjRoleService roleService;
    @Resource
    private ZjNetworkService networkService;
    @Resource
    private ZjNetworkEmpRelationService networkEmpRelationService;
    @Resource
    private ZjNetworkEmpService networkEmpService;

    // 登录
    @Override
    public AccountLoginToken login(LoginVo loginVo) throws SMSException {
        Assert.isTrue(Objects.equals(1, loginVo.getType()) || Objects.equals(2, loginVo.getType()), "登录类型不合法！", loginVo.getType());
        // 验证码
        if (Objects.equals(1, loginVo.getType())) {
            Assert.isTrue(VerificUtil.phoneVerific(loginVo.getPhone()), "请输入正确的手机号格式！", loginVo.getPhone());
            // 校验验证码
            PCSmsUtil.checkLoginVerificCode(loginVo.getPhone(), loginVo.getPassword());
        }
        ZjAccount account = accountService.getByPhoneOrAccount(loginVo.getPhone());
        Assert.isTrue(null != account, "该手机号不存在，请检查手机号是否输入错误！", loginVo.getPhone());
        Assert.isTrue(!Objects.equals(1, account.getStatus()), "该手机号已被冻结！", loginVo.getPhone());
        Assert.isTrue(!Objects.equals(2, account.getStatus()), "该手机号已被封禁！", loginVo.getPhone());

        if (Objects.equals(2, loginVo.getType())) {
            Assert.isTrue(Objects.equals(account.getPassword(), BCryptUtil.encryPassword(loginVo.getPassword(), account.getSalt())), "账号或密码错误！", null);
        }

        if (StpUtil.isLogin(account.getId())) {
            String oldAccessToken = StpUtil.getTokenValueByLoginId(account.getId(), DeviceType.PC.name());
            // 删除旧的登录缓存信息
            RedisLoginTokenUtil.removeAllTokenByAccessToken(oldAccessToken);
            RedisLoginTokenUtil.removeLoginAccessToken(oldAccessToken);
        }
        if (loginVo.getRememberMe()) {
            StpUtil.login(account.getId(),
                    new SaLoginModel()
                            .setDevice(DeviceType.PC.name()) // 登录端
                            .setIsLastingCookie(true) // 记住我
            );
        } else {
            StpUtil.login(account.getId(), DeviceType.PC.name());
        }
        AccounLoginInfo admInfo = new AccounLoginInfo(account.getId(), account.getAccount(), account.getPhone(), account.getName(), loginVo.getRememberMe(), DeviceType.PC.name());
        AccountLoginToken loginToken = TokenUtil.getLoginToken(admInfo);

        // 更新最后登录时间
        accountService.updateLastLoginTime(account.getId());
        return loginToken;
    }

    // 刷新token
    @Override
    public AccountLoginToken refreshToken(String refreshToken) throws LoginException {
        if (!RedisLoginTokenUtil.hasAccessTokenByRefreshToken(refreshToken)) {
            throw new LoginException("登录已过期，请重新登录！");
        }
        // 旧token
        String oldAccessToken = RedisLoginTokenUtil.getAccessTokenByRefreshToken(refreshToken);
        AccounLoginInfo admInfo = RedisLoginTokenUtil.getAccountLoginInfoByAccessToken(oldAccessToken);

        // 退出旧的登录
        StpUtil.logout(admInfo.getId(), admInfo.getDevice());

        // 重新登录
        if (admInfo.isRememberMe()) {
            StpUtil.login(admInfo.getId(),
                    new SaLoginModel()
                            .setDevice(admInfo.getDevice()) // 登录设备
                            .setIsLastingCookie(admInfo.isRememberMe()) // 记住我
                            .setTimeout(AccountConstant.LOGIN_TOKEN_REMEMBERME_EXPIRE_TIME) // 七天有效期
            );
        } else {
            StpUtil.login(admInfo.getId(), admInfo.getDevice());
        }
        // 删除旧的登录缓存信息
        RedisLoginTokenUtil.removeAllTokenByAccessToken(oldAccessToken);
        RedisLoginTokenUtil.removeLoginAccessToken(oldAccessToken);
        return TokenUtil.getLoginToken(admInfo);
    }

    // 获取与账号关联的所有企业
    @Override
    public LoginCustomerVo getCustomerByAccountId(AccounLoginInfo accountLoginInfo) {
        LoginCustomerVo customerVo = new LoginCustomerVo();
        customerVo.setPhone(accountLoginInfo.getPhone());
        customerVo.setName(accountLoginInfo.getName());

        // 获取商家ID集合
        List<Long> custAccIds = empService.getCustAccIdByAccountId(accountLoginInfo.getId());
        if (custAccIds.isEmpty()) {
            return customerVo;
        }
        // 获取角色
        List<ZjRole> roles = roleService.getByAccountIdAndCustAccIds(accountLoginInfo.getId(), custAccIds);
        List<ZjCustomer> customerList = customerService.listByIds(custAccIds);
        String aes = null;
        CustomerRoleVo customerRoleVo = null;
        for (ZjCustomer customer : customerList) {
            aes = UUID.randomUUID().toString();
            for (ZjRole role : roles) {
                if (Objects.equals(customer.getId(), role.getCustAccId())) {
                    customerRoleVo = CustomerRoleVo.beanToVo(customer, role.getName(), aes);
                    customerVo.getCustomerRoleVos().add(customerRoleVo);
                    RedisUtil.setCache(RedisConstant.ENTERPRISE_CODE + customerRoleVo.getCode(), aes, 5 * 60);
                }
            }
        }
        return customerVo;
    }

    // 选择企业
    @Override
    public void getCustomerCode(AccounLoginInfo accountLoginInfo, String code) {
        Assert.isTrue(RedisUtil.hasKey(RedisConstant.ENTERPRISE_CODE + code), "企业编码已过期，请重新获取！", null);
        String aesKey = (String) RedisUtil.getByKey(RedisConstant.ENTERPRISE_CODE + code);
        Long custAccId = Long.parseLong(BCryptUtil.aesDecry(aesKey, code));
        ZjCustomer customer = customerService.getById(custAccId);
        accountLoginInfo.setCustAccId(custAccId);
        accountLoginInfo.setCustAccLogoCode(customer.getLogoCode());
        accountLoginInfo.setCustAccAnnexCode(customer.getAnnexCode());
        accountLoginInfo.setCustAccVideoCode(customer.getVideoCode());
        ZjNetworkEmp byAccountId = networkEmpService.getByAccountId(accountLoginInfo.getId());
        if (byAccountId != null) {
            List<NetworkEmpRelationExtend> byNetworkEmpId = networkEmpRelationService.getByNetworkEmpId(byAccountId.getId());
            if (CollectionUtil.isNotEmpty(byNetworkEmpId)){
                accountLoginInfo.setNetworkId(byNetworkEmpId.get(0).getNetworkId());
            }
        }
    }
}
